package org.Yiran.timetale_re.block.decorate.longtable;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.Yiran.timetale_re.block.base.MultiBlockBase;
import org.Yiran.timetale_re.item.tool.chisel.base.ChiselItem;
import org.Yiran.timetale_re.tile.blocktile.LongTableBlockEntity;
import org.jetbrains.annotations.NotNull;

import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 长桌方块类 - 由两个部分组成的多方块结构
 * 支持物品放置、符文雕刻等功能
 * <p>
 * 结构说明:
 * - LEFT_PART (0): 左半部分，主方块，包含BlockEntity
 * - RIGHT_PART (1): 右半部分，辅助方块
 */
public class LongTable extends MultiBlockBase implements EntityBlock {
    // ==================== 方块属性定义 ====================
    
    /** 方向属性，继承自 MultiBlockBase */
    public static final DirectionProperty FACING = MultiBlockBase.FACING;
    
    /** 部件ID属性，用于区分左右两个部分 */
    public static final IntegerProperty PART_ID = IntegerProperty.create("part_id", 0, 1);

    // ==================== 部件常量定义 ====================
    
    /** 左半部分（主方块） */
    public static final int LEFT_PART = 0;
    
    /** 右半部分 */
    public static final int RIGHT_PART = 1;

    // ==================== 破坏锁定机制 ====================
    
    /** 添加破坏锁定机制防止重复破坏 */
    private static final Map<BlockPos, UUID> destructionLocks = new HashMap<>();

    // ==================== 构造函数和初始化 ====================

    /**
     * 构造函数
     * @param properties 方块属性
     * @param modId 模组ID
     * @param blockName 方块名称
     */
    public LongTable(Block.Properties properties, String modId, String blockName) {
        super(properties, modId, blockName, 2,
                (name, part) -> "models/block/decorate/" + name + "_" + (part == LEFT_PART ? "left" : "right") + ".json");
        this.registerDefaultState(this.stateDefinition.any()
                .setValue(FACING, Direction.NORTH)
                .setValue(PART_ID, LEFT_PART));
    }

    @Override
    public IntegerProperty getPartIdProperty() {
        return PART_ID;
    }

    // ==================== 多方块结构管理 ====================

    /**
     * 放置其他部分（右半部分）
     * 当主部分被放置时，这个方法负责放置结构的其他部分
     * 
     * @param level 世界对象
     * @param basePos 基础位置（左半部分位置）
     * @param facing 朝向
     * @param mainPartId 主部分ID
     */
    @Override
    protected void placeOtherParts(Level level, BlockPos basePos, Direction facing, int mainPartId) {
        // 放置右半部分
        BlockPos rightPos = basePos.relative(facing.getClockWise());
        BlockState rightState = this.defaultBlockState()
                .setValue(FACING, facing)
                .setValue(PART_ID, RIGHT_PART);
        level.setBlock(rightPos, rightState, 35);
    }

    /**
     * 检查是否可以放置长桌
     * 验证在指定位置和朝向是否可以放置整个多方块结构
     * 
     * @param level 世界对象
     * @param pos 放置位置
     * @param facing 朝向
     * @return 是否可以放置
     */
    @Override
    protected boolean canPlaceAt(Level level, BlockPos pos, Direction facing) {
        // 边界检查
        if (!isInWorldBounds(level, pos, facing)) {
            return false;
        }

        // 支撑检查
        if (!hasFullSupportBelow(level, pos, facing)) {
            return false;
        }

        // 空间可用性检查
        return isSpaceAvailable(level, pos, facing);
    }

    /**
     * 检查位置是否在世界边界内
     * @param level 世界对象
     * @param pos 放置位置
     * @param facing 朝向
     * @return 是否在边界内
     */
    private boolean isInWorldBounds(Level level, BlockPos pos, Direction facing) {
        BlockPos rightPos = pos.relative(facing.getClockWise());
        return level.isInWorldBounds(pos) && level.isInWorldBounds(rightPos);
    }

    /**
     * 检查下方是否有完整支撑
     * @param level 世界对象
     * @param pos 放置位置
     * @param facing 朝向
     * @return 是否有完整支撑
     */
    private boolean hasFullSupportBelow(Level level, BlockPos pos, Direction facing) {
        BlockPos posBelow = pos.below();
        BlockPos rightPosBelow = pos.relative(facing.getClockWise()).below();
        BlockState belowState = level.getBlockState(posBelow);
        BlockState rightBelowState = level.getBlockState(rightPosBelow);

        return isFullBlock(belowState) && isFullBlock(rightBelowState);
    }

    /**
     * 检查空间是否可用（可以被替换）
     * @param level 世界对象
     * @param pos 放置位置
     * @param facing 朝向
     * @return 空间是否可用
     */
    private boolean isSpaceAvailable(Level level, BlockPos pos, Direction facing) {
        BlockState leftState = level.getBlockState(pos);
        BlockState rightState = level.getBlockState(pos.relative(facing.getClockWise()));
        return leftState.canBeReplaced() && rightState.canBeReplaced();
    }

    /**
     * 检查部件是否有效
     * 检查多方块结构的各个部分是否仍然有效连接
     * 
     * @param level 世界对象
     * @param pos 部件位置
     * @param facing 朝向
     * @param partId 部件ID
     * @return 部件是否有效
     */
    @Override
    protected boolean isPartValid(LevelReader level, BlockPos pos, Direction facing, int partId) {
        // 检查下方是否有完整方块支撑
        BlockPos posBelow = pos.below();
        BlockState belowState = level.getBlockState(posBelow);
        if (!isFullBlock(belowState)) {
            return false;
        }

        if (partId == LEFT_PART) {
            // 左半部分需要检查右半部分是否存在且有效
            return isAdjacentPartValid(level, pos, facing, facing.getClockWise(), RIGHT_PART);
        } else {
            // 右半部分需要检查左半部分是否存在且有效
            return isAdjacentPartValid(level, pos, facing, facing.getCounterClockWise(), LEFT_PART);
        }
    }

    /**
     * 检查相邻部分是否有效
     * @param level 世界
     * @param pos 当前位置
     * @param facing 朝向
     * @param offsetDirection 偏移方向
     * @param expectedPartId 期望的部分ID
     * @return 相邻部分是否有效
     */
    private boolean isAdjacentPartValid(LevelReader level, BlockPos pos, Direction facing, Direction offsetDirection, int expectedPartId) {
        BlockPos adjacentPos = pos.relative(offsetDirection);
        BlockPos adjacentPosBelow = adjacentPos.below();
        BlockState adjacentBelowState = level.getBlockState(adjacentPosBelow);

        // 检查相邻部分下方是否有完整方块支撑
        if (!isFullBlock(adjacentBelowState)) {
            return false;
        }

        BlockState adjacentState = level.getBlockState(adjacentPos);
        return adjacentState.getBlock() == this &&
                adjacentState.getValue(FACING) == facing &&
                adjacentState.getValue(PART_ID) == expectedPartId;
    }

    /**
     * 检查方块是否能存活（下方有支撑）
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     * @return 是否能存活
     */
    @Override
    public boolean canSurvive(@NotNull BlockState state, @NotNull LevelReader level, @NotNull BlockPos pos) {
        // 检查下方是否有完整方块支撑
        BlockPos posBelow = pos.below();
        BlockState belowState = level.getBlockState(posBelow);
        return isFullBlock(belowState);
    }

    /**
     * 邻近方块变化时的处理
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     * @param block 变化的方块
     * @param fromPos 变化的位置
     * @param isMoving 是否在移动
     */
    @Override
    @SuppressWarnings("deprecation")
    public void neighborChanged(@NotNull BlockState state, @NotNull Level level, BlockPos pos, @NotNull Block block, BlockPos fromPos, boolean isMoving) {
        // 检查下方的方块是否被移除
        BlockPos posBelow = pos.below();
        if (fromPos.equals(posBelow)) {
            BlockState belowState = level.getBlockState(posBelow);
            if (!isFullBlock(belowState)) {
                // 如果下方方块不再是完整方块，则破坏整个长桌
                // 使用dropResources方法确保掉落物品
                this.destroyAndDrop(state, level, pos);
                return;
            }
        }
        super.neighborChanged(state, level, pos, block, fromPos, isMoving);
    }

    /**
     * 破坏方块并确保掉落物品
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     */
    private void destroyAndDrop(BlockState state, Level level, BlockPos pos) {
        Direction facing = state.getValue(FACING);
        int partId = state.getValue(PART_ID);

        // 移除整个结构
        removeAllParts(level, pos, facing, partId);

        // 处理物品掉落
        handleItemDrop(level, pos, partId);
    }

    /**
     * 处理物品掉落
     * @param level 世界对象
     * @param pos 方块位置
     * @param partId 部件ID
     */
    private void handleItemDrop(Level level, BlockPos pos, int partId) {
        // 只有主部分（左半部分）负责掉落物品
        if (partId == LEFT_PART) {
            popResource(level, pos, new ItemStack(this));
        }
    }

    /**
     * 移除其他部分
     * 当主部分被移除时，清理结构的其他部分
     * 
     * @param level 世界对象
     * @param pos 方块位置
     * @param facing 朝向
     * @param partId 部件ID
     */
    @Override
    protected void removeOtherParts(Level level, BlockPos pos, Direction facing, int partId) {
        if (level.isClientSide) {
            return;
        }

        if (partId == LEFT_PART) {
            removeRightPart(level, pos, facing);
        } else {
            removeLeftPartAndUpdateEntity(level, pos, facing);
        }
    }

    /**
     * 移除右半部分
     * @param level 世界对象
     * @param pos 方块位置
     * @param facing 朝向
     */
    private void removeRightPart(Level level, BlockPos pos, Direction facing) {
        BlockPos rightPos = pos.relative(facing.getClockWise());
        BlockState rightState = level.getBlockState(rightPos);
        if (rightState.getBlock() == this) {
            level.destroyBlock(rightPos, true);
        }
    }

    /**
     * 移除左半部分并更新方块实体
     * @param level 世界对象
     * @param pos 方块位置
     * @param facing 朝向
     */
    private void removeLeftPartAndUpdateEntity(Level level, BlockPos pos, Direction facing) {
        BlockPos leftPos = pos.relative(facing.getCounterClockWise());
        BlockState leftState = level.getBlockState(leftPos);
        if (leftState.getBlock() == this) {
            level.destroyBlock(leftPos, true);
            updateLeftBlockEntity(level, leftPos);
        }
    }

    /**
     * 更新左侧方块实体中的数据
     * @param level 世界对象
     * @param leftPos 左侧方块位置
     */
    private void updateLeftBlockEntity(Level level, BlockPos leftPos) {
        BlockEntity be = level.getBlockEntity(leftPos);
        if (be instanceof LongTableBlockEntity tableEntity) {
            tableEntity.removeItem(LongTable.RIGHT_PART);
            tableEntity.setChanged();
            // 强制更新客户端
            BlockState leftStateUpdated = level.getBlockState(leftPos);
            level.sendBlockUpdated(leftPos, leftStateUpdated, leftStateUpdated, Block.UPDATE_ALL);
        }
    }

    /**
     * 移除整个多方块结构，确保破坏粒子效果和物品掉落
     */
    private void removeAllParts(Level level, BlockPos pos, Direction facing, int partId) {
        if (!level.isClientSide) {
            // 先移除其他部分
            removeOtherParts(level, pos, facing, partId);
            // 然后移除自身部分
            level.removeBlock(pos, false);
        }
    }

    /**
     * 获取部件位置
     * @param basePos 基础位置
     * @param facing 朝向
     * @param partId 部件ID
     * @return 部件位置
     */
    @Override
    protected BlockPos getPartPosition(BlockPos basePos, Direction facing, int partId) {
        return switch (partId) {
            case LEFT_PART -> basePos;
            case RIGHT_PART -> basePos.relative(facing.getClockWise());
            default -> null;
        };
    }

    /**
     * 获取预期邻居位置
     * @param pos 方块位置
     * @param facing 朝向
     * @param partId 部件ID
     * @return 预期邻居位置
     */
    @Override
    protected BlockPos getExpectedNeighborPos(BlockPos pos, Direction facing, int partId) {
        return switch (partId) {
            case LEFT_PART -> pos.relative(facing.getClockWise());  // 左半部分邻居在右侧
            case RIGHT_PART -> pos.relative(facing.getCounterClockWise()); // 右半部分邻居在左侧
            default -> null;
        };
    }

    /**
     * 预放置视觉效果（客户端）
     * @param level 世界对象
     * @param basePos 基础位置
     * @param facing 朝向
     */
    @Override
    protected void prePlaceVisual(Level level, BlockPos basePos, Direction facing) {
        if (level.isClientSide) {
            // 预放置右半部分（part_id=1）
            BlockPos partPos = getPartPosition(basePos, facing, RIGHT_PART);
            if (partPos != null) {
                BlockState partState = this.defaultBlockState()
                        .setValue(FACING, facing)
                        .setValue(PART_ID, RIGHT_PART);
                // 使用 Block.UPDATE_IMMEDIATE | Block.UPDATE_KNOWN_SHAPE 确保立即显示
                level.setBlock(partPos, partState, 10);
            }
        }
    }

    // ==================== 方块交互处理 ====================

    /**
     * 方块使用处理
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     * @param player 玩家
     * @param hand 手部
     * @param hit 点击结果
     * @return 交互结果
     */
    @Override
    @SuppressWarnings("deprecation")
    public @NotNull InteractionResult use(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, Player player, @NotNull InteractionHand hand, @NotNull BlockHitResult hit) {
        ItemStack heldItem = player.getItemInHand(hand);

        if (shouldSkipInteraction(player)) {
            return InteractionResult.PASS;
        }

        if (isChiselItem(heldItem)) {
            return handleChiselInteraction(state, level, pos, player, hand, hit);
        }

        return handleItemPlacementOrRetrieval(state, level, pos, player, hand, hit);
    }

    /**
     * 检查是否应该跳过交互（玩家潜行时）
     * @param player 玩家
     * @return 是否跳过交互
     */
    private boolean shouldSkipInteraction(Player player) {
        return player.isShiftKeyDown();
    }

    /**
     * 检查是否为凿子物品
     * @param itemStack 物品堆
     * @return 是否为凿子
     */
    private boolean isChiselItem(ItemStack itemStack) {
        return itemStack.getItem() instanceof ChiselItem;
    }

    /**
     * 处理凿子交互
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     * @param player 玩家
     * @param hand 手部
     * @param hit 点击结果
     * @return 交互结果
     */
    private InteractionResult handleChiselInteraction(BlockState state, Level level, BlockPos pos,
                                                      Player player, InteractionHand hand, BlockHitResult hit) {
        return LongTableCarvingHandler.handleChiselUse(state, level, pos, player, hand, hit);
    }

    /**
     * 处理物品放置或取回
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     * @param player 玩家
     * @param hand 手部
     * @param hit 点击结果
     * @return 交互结果
     */
    private InteractionResult handleItemPlacementOrRetrieval(BlockState state, Level level, BlockPos pos,
                                                             Player player, InteractionHand hand, BlockHitResult hit) {
        return LongTableItemHandler.handleItemInteraction(state, level, pos, player, hand, hit);
    }

    // ==================== 物品掉落处理 ====================

    /**
     * 移除方块时掉落物品
     * 当多方块结构被移除时，处理物品掉落逻辑
     * 
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     */
    @Override
    protected void dropItemsOnRemove(BlockState state, Level level, BlockPos pos) {
        // 只有主部分（左半部分）负责掉落物品
        if (state.getValue(PART_ID) == LEFT_PART) {
            BlockEntity blockEntity = level.getBlockEntity(pos);
            if (blockEntity instanceof LongTableBlockEntity tableEntity) {
                // 掉落左半部分的物品
                if (!tableEntity.leftItem.isEmpty()) {
                    popResource(level, pos, tableEntity.leftItem);
                }
                // 掉落右半部分的物品
                if (!tableEntity.rightItem.isEmpty()) {
                    popResource(level, pos, tableEntity.rightItem);
                }
            }
        }
    }

    // ==================== 辅助方法 ====================

    /**
     * 获取物品在世界中的渲染位置
     * @param pos 方块位置
     * @param partId 部件ID
     * @param facing 朝向
     * @param tableEntity 长桌方块实体
     * @return 渲染位置
     */
    public static Vec3 getItemRenderPosition(BlockPos pos, int partId, Direction facing, LongTableBlockEntity tableEntity) {
        // 获取物品偏移
        float itemXOffset = tableEntity.getItemXOffset(partId);
        float itemZOffset = tableEntity.getItemZOffset(partId);

        // 根据朝向调整偏移坐标系
        float adjustedXOffset = itemXOffset;
        float adjustedZOffset = itemZOffset;

        switch (facing) {
            case NORTH -> {
                adjustedXOffset = itemZOffset;
                adjustedZOffset = -itemXOffset;
            }
            case SOUTH -> {
                adjustedXOffset = -itemZOffset;
                adjustedZOffset = itemXOffset;
            }
            case WEST -> {
                adjustedXOffset = itemXOffset;
                adjustedZOffset = itemZOffset;
            }
            case EAST -> {
                adjustedXOffset = -itemXOffset;
                adjustedZOffset = -itemZOffset;
            }
        }

        // 计算基础位置
        double baseX = pos.getX() + 0.5;
        double baseY = pos.getY() + 0.77; // 与渲染器中一致的高度
        double baseZ = pos.getZ() + 0.5;

        // 应用偏移
        double finalX = baseX + adjustedXOffset;
        double finalZ = baseZ + adjustedZOffset;

        // 对于右半部分，需要根据朝向调整基础位置
        if (partId == LongTable.RIGHT_PART) {
            switch (facing) {
                case NORTH -> finalX += 1.0;
                case SOUTH -> finalX -= 1.0;
                case WEST -> finalZ -= 1.0;
                case EAST -> finalZ += 1.0;
            }
        }

        return new Vec3(finalX, baseY, finalZ);
    }

    /**
     * 获取主方块位置（左半部分）
     * @param pos 当前位置
     * @param state 方块状态
     * @return 主方块位置
     */
    static BlockPos getMainPos(BlockPos pos, BlockState state) {
        Direction facing = state.getValue(LongTable.FACING);
        int partId = state.getValue(LongTable.PART_ID);

        if (partId == LongTable.LEFT_PART) {
            return pos;
        } else {
            // 如果是右半部分，计算左半部分的位置
            return pos.relative(facing.getCounterClockWise());
        }
    }

    /**
     * 根据当前位置和主位置计算部件ID
     * @param pos 当前位置
     * @param mainPos 主位置
     * @param facing 朝向
     * @return 部件ID
     */
    private int getPartId(BlockPos pos, BlockPos mainPos, Direction facing) {
        if (pos.equals(mainPos)) {
            return LEFT_PART;
        } else {
            return RIGHT_PART;
        }
    }

    /**
     * 检查方块是否为完整方块（具有完整的碰撞箱）
     * @param state 方块状态
     * @return 是否为完整方块
     */
    private boolean isFullBlock(BlockState state) {
        if (state == null || state.getBlock() == Blocks.AIR) {
            return false;
        }
        // 检查是否为完整方块形状
        return Shapes.joinIsNotEmpty(state.getCollisionShape(null, null), Shapes.block(), BooleanOp.AND);
    }

    // ==================== 方块实体相关 ====================

    /**
     * 创建方块实体
     * @param pos 方块位置
     * @param state 方块状态
     * @return 方块实体
     */
    @Override
    public BlockEntity newBlockEntity(@NotNull BlockPos pos, BlockState state) {
        // 只有主部分创建BlockEntity
        if (state.getValue(PART_ID) == LEFT_PART) {
            return new LongTableBlockEntity(pos, state);
        }
        return null;
    }

    /**
     * 获取方块实体更新器
     * @param level 世界对象
     * @param state 方块状态
     * @param blockEntityType 方块实体类型
     * @param <T> 方块实体类型
     * @return 方块实体更新器
     */
    @Nullable
    @Override
    public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, @NotNull BlockState state, @NotNull BlockEntityType<T> blockEntityType) {
        if (level.isClientSide) {
            return null;
        }
        return (lvl, pos, st, blockEntity) -> {
        };
    }
}